#include <iostream>
#include "xstub.hpp"
using namespace std;

#define CHECK_PSELECT_TIMEOUT	3	// min timeout value
#define CHECK_STATE_INTERVAL	3
#define CHECK_PROXY_INTERVAL	60

xstub::xstub(){

	SAY( DP_DEBUG , "In constuctor function of xstub \n" );
	
	manager_p	= NULL;

	producer_p 	= NULL;
	producer_type 	= DAHUA_DEV;

	xtreamsrv_p	= NULL;
	xtreamsrv_type 	= XTREAM_SRV;
	
	inited		= FALSE;
	
	bQuit		= FALSE;	
}

xstub::~xstub(){

	SAY( DP_DEBUG , "In distructor function of xstub \n" );

	uninit();

	if( manager_p ){
		delete  manager_p;
		manager_p= NULL;
	}
}

BOOL
xstub::initialize(){
	SAY( DP_DEBUG , "In initialize function of xstub \n" );

	if( inited ){
		return TRUE;
	}

	producer_p = object_builder::create_producer( producer_type );
	if( !producer_p ){
		SAY( DP_DEBUG , "Failed to create PRODUCER object! \n");
		return FALSE ;
	}
	
	xtreamsrv_p= object_builder::create_server( xtreamsrv_type );
	if( !xtreamsrv_p ){
		SAY( DP_DEBUG , "Failed to create SERVER object! \n")
		return FALSE;
	}

	/** 
	 * Because manager send parameters to xstub at xstub startup only,
	 * manager_p is allocated and communicates with manager only once,
	 * and if manager_p receives parameter from manager incorrectly, quit.
	 */
	if( !manager_p ){
		manager_p = new manager_adapter();
		if( ! manager_p->get_params() ){
			SAY( DP_DEBUG , "get parameters form manager failed ! \n" );
			quit();
			return FALSE;
		}
	}
	
	if( FALSE == producer_p->configure( manager_p->params ) ){
		SAY( DP_DEBUG , "Producer configure failed!\n");
		return FALSE;
	}

	xtreamsrv_p->configure( manager_p->params );
	
	inited = TRUE;

	return TRUE;
}

void
xstub::uninit(){

	SAY( DP_DEBUG , "In uninitialize function of xstub \n" );
//	if( !inited ){
//		return;
//	}

	inited = FALSE;

	if( xtreamsrv_p ){
		xtreamsrv_p->disconnect();
		xtreamsrv_p->uninit();
		delete xtreamsrv_p;
		xtreamsrv_p = NULL;
	}

	if( producer_p ){	
		producer_p->disconnect();
		producer_p->uninit();
		delete producer_p;
		producer_p = NULL;
	}

	return;
}

BOOL
xstub::run(){
	

	SAY( DP_DEBUG , "In run function of xstub \n" );

        struct timespec tvspec;
	tvspec.tv_sec = CHECK_PSELECT_TIMEOUT;
        tvspec.tv_nsec = 0;

	selector sel( tvspec );

	try{
		SAY( DP_DEBUG , "Initialize Producer!\n" );
		producer_p->initialize();

		SAY( DP_DEBUG, "Connect Producer!\n" );
		producer_p->connect();
		
	}catch( ... ){

		SAY( DP_DEBUG , "Producer_adapter Failed! throw out\n" );
		return FALSE;
	}

	SAY( DP_DEBUG , "Initialize Xtreamsrv!\n");
	xtreamsrv_p->initialize( producer_p );

	SAY( DP_DEBUG , "Connect Xtreamsrv!\n");
	if( FALSE == xtreamsrv_p->connect() ){
		SAY(DP_DEBUG,"Xtreamsrv_adapter failed! throw out \n");
		return FALSE;
	}

	sel.set_fd( xtreamsrv_p );
//	sel.set_fd( manager_p );
//#ifdef _USEDAEMON
	if ( op_by_thread( &pipe_thread, (long unsigned int)manager_p , 0 ) < 0 ) {
		SAY( DP_DEBUG, "<ERROR_LOG>pipe_thread create error\n" );
		return FALSE;
	}
//#endif
 

	xtreamsrv_p->set_proxy_fd( &sel );

	time_t chkstate_time = time(NULL)+CHECK_STATE_INTERVAL;
	time_t chkproxy_time = time(NULL)+CHECK_PROXY_INTERVAL;
	time_t curr_time;
	while( 1 ){

		sel.select();

		curr_time = time(NULL);
		if ( curr_time>=chkstate_time ) {
		xtreamsrv_p->check_state();
			chkstate_time = curr_time + CHECK_STATE_INTERVAL;
		}
		if ( curr_time>=chkproxy_time ) {
		xtreamsrv_p->check_proxy();
			chkproxy_time = curr_time + CHECK_PROXY_INTERVAL;
		}

		if( manager_p->is_manager_quit() ){
			SAY( DP_DEBUG , "manager quit!\n" );
			quit();
			return FALSE;
		}

		if( producer_p->is_prod_quit() ){
			SAY( DP_DEBUG , "producer quit!\n" );
			return FALSE;
		}

		if( xtreamsrv_p->is_server_quit() ){
			SAY( DP_DEBUG , "server quit!\n" );
			return FALSE;
		}
		

	}

	return TRUE;
	
}

BOOL
xstub::is_quit(){

	return bQuit;
}

void 
xstub::quit() {

	SAY( DP_DEBUG, "Gross error in xstub !\n" );
	bQuit = TRUE;


//	raise( CHILD_CON_SIGNAL ); // make sleeped main program to waked

//	alarm( 5 ); // quit after 60 second

	return ;
}

